﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gargoyle.Roton
{
    public abstract class MemoryAccessBase
    {
        protected byte[] mem;
        protected int offset;

        public bool GetBool()
        {
            return GetBool(0);
        }

        public bool GetBool(int offset)
        {
            return GetByte(offset) != 0;
        }

        public byte GetByte()
        {
            return GetByte(0);
        }

        public byte GetByte(int offset)
        {
            return mem[this.offset + offset];
        }

        public Int16 GetInt16()
        {
            return GetInt16(0);
        }

        public Int16 GetInt16(int offset)
        {
            Int16 result;
            result = mem[this.offset + offset + 1];
            result <<= 8;
            result |= (Int16)mem[this.offset + offset];
            return result;
        }

        public Int32 GetInt32()
        {
            return GetInt32(0);
        }

        public Int32 GetInt32(int offset)
        {
            Int32 result;
            result = mem[this.offset + offset + 3];
            result <<= 8;
            result |= (Int32)mem[this.offset + offset + 2];
            result <<= 8;
            result |= (Int32)mem[this.offset + offset + 1];
            result <<= 8;
            result |= (Int32)mem[this.offset + offset];
            return result;
        }

        public Pointer GetRelativePointer(int offset)
        {
            return new Pointer(mem, this.offset + offset);
        }

        public ByteString GetString()
        {
            return GetString(0);
        }

        public ByteString GetString(int offset)
        {
            int length = mem[this.offset + offset];
            byte[] data = new byte[length];
            Array.Copy(mem, this.offset + offset + 1, data, 0, length);
            return new ByteString(data);
        }

        public void SetBool(bool value)
        {
            SetBool(0, value);
        }

        public void SetBool(int offset, bool value)
        {
            SetByte(offset, (byte)(value ? 1 : 0));
        }

        public void SetByte(byte value)
        {
            SetByte(0, value);
        }

        public void SetByte(int offset, byte value)
        {
            mem[this.offset + offset] = value;
        }

        public void SetInt16(Int16 value)
        {
            SetInt16(0, value);
        }

        public void SetInt16(int offset, Int16 value)
        {
            mem[this.offset + offset] = (byte)(value & 0xFF);
            value >>= 8;
            mem[this.offset + offset + 1] = (byte)(value & 0xFF);
        }

        public void SetInt32(Int32 value)
        {
            SetInt32(0, value);
        }

        public void SetInt32(int offset, Int32 value)
        {
            mem[this.offset + offset] = (byte)(value & 0xFF);
            value >>= 8;
            mem[this.offset + offset + 1] = (byte)(value & 0xFF);
            value >>= 8;
            mem[this.offset + offset + 2] = (byte)(value & 0xFF);
            value >>= 8;
            mem[this.offset + offset + 3] = (byte)(value & 0xFF);
        }

        public void SetString(ByteString value)
        {
            SetString(0, value);
        }

        public void SetString(int offset, ByteString value)
        {
            int length = value.Length & 0xFF;
            mem[this.offset + offset] = (byte)length;
            Array.Copy(value, 0, mem, this.offset + offset + 1, length);
        }
    }

    sealed public class Heap
    {
        Dictionary<int, ByteString> table = new Dictionary<int, ByteString>();
        int uid;

        public Heap()
        {
            Clear();
        }

        public ByteString this[int handle]
        {
            get { return table[handle]; }
        }

        public int Allocate(ByteString data)
        {
            unchecked
            {
                uid++;
            }
            table[uid] = data;
            return uid;
        }

        public void Clear()
        {
            table.Clear();
            uid = int.MinValue;
        }

        public void Free(int handle)
        {
            if (table.ContainsKey(handle))
                table.Remove(handle);
        }
    }

    sealed public class Memory : MemoryAccessBase
    {
        public Memory(int capacity)
        {
            this.mem = new byte[capacity];
        }

        public Memory(byte[] memblock)
        {
            this.mem = memblock;
        }

        public Pointer this[int offset]
        {
            get
            {
                return new Pointer(mem, offset);
            }
        }
    }

    sealed public class Pointer : MemoryAccessBase
    {
        public Pointer(byte[] data)
        {
            this.mem = data;
            this.offset = 0;
        }

        public Pointer(byte[] data, int offset)
        {
            this.mem = data;
            this.offset = offset;
        }

        public byte this[int index]
        {
            get
            {
                return mem[offset + index];
            }
            set
            {
                mem[offset + index] = value;
            }
        }

        public bool Bool
        {
            get { return GetBool(); }
            set { SetBool(value); }
        }

        public byte Byte
        {
            get { return GetByte(); }
            set { SetByte(value); }
        }

        public Int16 Int16
        {
            get { return GetInt16(); }
            set { SetInt16(value); }
        }

        public Int32 Int32
        {
            get { return GetInt32(); }
            set { SetInt32(value); }
        }

        public ByteString String
        {
            get { return GetString(); }
            set { SetString(value); }
        }
    }
}
